import {
  SpringStarter,
  Component,
  Value,
  Clazz,
  Logger,
  Autowired,
} from 'j-spring';
import { ClazzExtendsMap } from 'j-spring/dist/SpringFactry';
import { DataSource, DataSourceOptions } from 'typeorm';
import { LoggerAdaptor } from './LoggerAdaptor';
import { EntityClass } from './SpringJpaEntity';

const entityList: EntityClass[] = [];

const logger = new LoggerAdaptor();

export function loadEntity(entities: EntityClass[]): void {
  entities.forEach(e => entityList.push(e));
}

const modulePrefix = 'j-spring-jpa';

abstract class BaseDataSourceConnect implements SpringStarter {
  @Value({ path: `${modulePrefix}.logging`, force: false })
  logging: boolean = true;

  @Value({ path: `${modulePrefix}.synchronize`, force: false })
  synchronize: boolean = true;

  @Autowired()
  log: Logger;

  public async doStart(clazzMap: ClazzExtendsMap): Promise<any> {
    const { logging, synchronize, log } = this;

    const profile = {
      logging,
      synchronize,
      logger,
    };
    const options = this.getOptions();

    const dataSource = new DataSource({ ...profile, ...options });

    await dataSource.initialize();

    log.info(`sqlite启动成功`);

    clazzMap.addBean(
      DataSource as Clazz,
      dataSource,
      'typeorm数据配置-DataSource'
    );
  }
  public isSpringStater(): boolean {
    return true;
  }
  abstract getOptions(): DataSourceOptions;
}

@Component()
export class SqliteStarter extends BaseDataSourceConnect {
  @Value({ path: `${modulePrefix}.name`, force: false })
  name: string = 'sqlite';

  @Value({ path: `${modulePrefix}.database`, force: false })
  database: string = './data.db';

  getOptions(): DataSourceOptions {
    const { name, database } = this;
    const options: DataSourceOptions = {
      name,
      type: 'sqlite',
      database,
      entities: entityList,
    };
    return options;
  }
}

@Component()
export class MysqlStarter extends BaseDataSourceConnect {
  @Value({ path: `${modulePrefix}.host` })
  host: string;

  @Value({ path: `${modulePrefix}.port`, force: false })
  port: number = 3306;

  @Value({ path: `${modulePrefix}.database` })
  database: string;

  @Value({ path: `${modulePrefix}.username` })
  username: string;

  @Value({ path: `${modulePrefix}.password` })
  password: string;

  getOptions(): DataSourceOptions {
    const { host, port, username, password, database } = this;
    const options: DataSourceOptions = {
      host,
      port,
      username,
      password,
      type: 'mysql',
      database,
      entities: entityList,
    };
    return options;
  }
}
